package perform.session;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;

import perform.broker.DatabaseBroker;
import perform.broker.ExtendedDatabaseBroker;
import perform.broker.SimpleDatabaseBroker;
import perform.connection.ConnectionManager;
import perform.criterion.Criterion;
import perform.criterion.Order;
import perform.type.Type;

public class SessionImpl implements Session {
	
	private ConnectionManager pool;
	private DatabaseBroker broker;
	
	SessionImpl(ConnectionManager pool, String write){
		this.pool = pool;
		if(write.equals("true")){
			broker = new ExtendedDatabaseBroker();
		} else {
			broker = new SimpleDatabaseBroker();
		}
	}

	@Override
	public <T extends Type> T save(T type) {
		try {
			Connection connection = pool.getConnection();
			try {
				type = broker.save(type, connection);
				connection.commit();
			} catch (Exception e) {
				if(e instanceof SQLException){
					connection.rollback();
				}
				connection.close();
				throw e;
			}
			connection.close();
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
		return type;
	}

	@Override
	public <T extends Type> List<T> save(List<T> types) {
		try {
			Connection connection = pool.getConnection();
			try {
				for(int i = 0; i < types.size(); i++){
					types.set(i, broker.save(types.get(i), connection));
				}
				connection.commit();
			} catch (Exception e) {
				if(e instanceof SQLException){
					connection.rollback();
				}
				connection.close();
				throw e;
			}
			connection.close();
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
		return types;
	}

	@Override
	public <T extends Type> void update(T type) {
		try {
			Connection connection = pool.getConnection();
			try {
				broker.update(type, connection);
				connection.commit();
			} catch (Exception e) {
				if(e instanceof SQLException){
					connection.rollback();
				}
				connection.close();
				throw e;
			}
			connection.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	@Override
	public <T extends Type> void update(List<T> types) {
		try {
			Connection connection = pool.getConnection();
			try {
				for(int i = 0; i < types.size(); i++){
					broker.update(types.get(i), connection);
				}
				connection.commit();
			} catch (Exception e) {
				if(e instanceof SQLException){
					connection.rollback();
				}
				connection.close();
				throw e;
			}
			connection.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	@Override
	public <T extends Type> void delete(T type) {
		try {
			Connection connection = pool.getConnection();
			try {
				broker.delete(type, connection);
				connection.commit();
			} catch (Exception e) {
				if(e instanceof SQLException){
					connection.rollback();
				}
				connection.close();
				throw e;
			}
			connection.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	@Override
	public <T extends Type> void delete(List<T> types) {
		try {
			Connection connection = pool.getConnection();
			try {
				for(int i = 0; i < types.size(); i++){
					broker.delete(types.get(i), connection);
				}
				connection.commit();
			} catch (Exception e) {
				if(e instanceof SQLException){
					connection.rollback();
				}
				connection.close();
				throw e;
			}
			connection.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	@Override
	public <T extends Type> T get(T type) {
		try {
			Connection connection = pool.getConnection();
			try {
				type = broker.get(type, connection);
				connection.commit();
			} catch (SQLException e) {
				connection.rollback();
				throw e;
			}
			connection.close();
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
		return type;
	}

	@Override
	public <T extends Type> List<T> get(Class<T> clazz, Criterion criterion) {
		try {
			Connection connection = pool.getConnection();
			List<T> results = broker.get(clazz, criterion, connection);
			connection.close();
			return results;
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	@Override
	public <T extends Type> List<T> get(Class<T> clazz, Criterion criterion,
			Order order) {
		try {
			Connection connection = pool.getConnection();
			List<T> results = broker.get(clazz, criterion, order, connection);
			connection.close();
			return results;
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	@Override
	public <T extends Type> List<T> get(Class<T> clazz, Criterion criterion,
			Order order, int lowLimit, int highLimit) {
		try {
			Connection connection = pool.getConnection();
			List<T> results = broker.get(clazz, criterion, order, lowLimit, highLimit, connection);
			connection.close();
			return results;
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	@Override
	public <T extends Type> List<T> get(Class<T> clazz, String criteria) {
		try {
			Connection connection = pool.getConnection();
			List<T> results = broker.get(clazz, criteria, connection);
			connection.close();
			return results;
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	@Override
	public <T extends Type> List<T> get(Class<T> clazz, String criteria,
			Order order) {
		try {
			Connection connection = pool.getConnection();
			List<T> results = broker.get(clazz, criteria, order, connection);
			connection.close();
			return results;
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	@Override
	public <T extends Type> List<T> get(Class<T> clazz, String criteria,
			Order order, int lowLimit, int highLimit) {
		try {
			Connection connection = pool.getConnection();
			List<T> results = broker.get(clazz, criteria, order, lowLimit, highLimit, connection);
			connection.close();
			return results;
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	@Override
	public <T extends Type> List<T> getCustom(Class<T> clazz, String from) {
		try {
			Connection connection = pool.getConnection();
			List<T> results = broker.getCustom(clazz, from, connection);
			connection.close();
			return results;
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	@Override
	public void customUpdate(String query) {
		try {
			Connection connection = pool.getConnection();
			try {
				broker.customUpdate(query, connection);
				connection.commit();
			} catch (Exception e) {
				if(e instanceof SQLException){
					connection.rollback();
				}
				connection.close();
				throw e;
			}
			connection.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

}
